/****************************************************************************
 * Copyright 2009 Huascar A. Sanchez                                        *
 *                                                                          *
 * Licensed under the Apache License, Version 2.0 (the "License");          *
 * you may not use this file except in compliance with the License.         *
 * You may obtain a copy of the License at                                  *
 *                                                                          *
 *     http://www.apache.org/licenses/LICENSE-2.0                           *
 *                                                                          *
 * Unless required by applicable law or agreed to in writing, software      *
 * distributed under the License is distributed on an "AS IS" BASIS,        *
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. *
 * See the License for the specific language governing permissions and      *
 * limitations under the License.                                           *
 ****************************************************************************/
package com.gotobject.filter.spi;

import com.gotobject.filter.Filter;
import com.gotobject.filter.predicate.Predicate;

import java.util.Iterator;
import java.util.NoSuchElementException;

/**
 * @author huascar.sanchez@gmail.com (Huascar A. Sanchez)
 */
public class FilteringImpl <T> implements Filtering <T> {
    private final   Filter                  filter;

    public FilteringImpl(Filter filter){
        this.filter = filter;
    }

    @Override
    public Iterable<T> filter(final Predicate<? super T> predicate, final Iterable<T> source) {
        return new Iterable<T>(){
            @Override
            public Iterator<T> iterator() {
                return new FilteringIterator<T>(predicate, source.iterator(), filter);
            }
        };
    }

    /**
     *
     * @param <T> bound type
     */
    private static class FilteringIterator<T> implements Iterator<T> {
        private final Predicate<? super T> predicate;
        private final       Iterator <T>          base;
        private final       Filter                filter;
        private volatile    T                     next;

        FilteringIterator(Predicate<? super T> predicate, Iterator<T> base, Filter filter){
            this.predicate  = predicate;
            this.base       = base;
            this.filter     = filter;
            tryFilteringNext();
        }

        private void tryFilteringNext() {
            next = null;
            synchronized (base){
                for(Iterator<T> itr = base; itr.hasNext();){
                    try {
                        final T item = base.next();
                        if (item != null && predicate.apply(item)) {
                            next = item;
                            break;
                        }
                    } catch (RuntimeException e){
                        filter.addError(e);
                    }
                }
            }
        }

        @Override
        public boolean hasNext() {
            return next != null;
        }

        @Override
        public T next() {
            if (next == null) throw new NoSuchElementException();
            final T returnValue = next;
            tryFilteringNext();
            return returnValue;
        }

        @Override
        public void remove() {
            throw new UnsupportedOperationException();
        }
    }
}
